/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.planning.tactical;

import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Date;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
import nl.cloudfarming.client.crop.Crop;
import nl.cloudfarming.client.crop.CropService;
import nl.cloudfarming.client.crop.Race;
import nl.cloudfarming.client.logging.AppLogFactory;
import nl.cloudfarming.client.logging.AppLogger;
import nl.cloudfarming.client.messaging.Message;
import nl.cloudfarming.client.messaging.MessageEvent;
import nl.cloudfarming.client.messaging.MessageEventKey;
import nl.cloudfarming.client.messaging.MessageEventProducer;
import nl.cloudfarming.client.model.Field;
import nl.cloudfarming.client.model.ProductionUnit;
import nl.cloudfarming.client.model.ProductionUnitAction;
import nl.cloudfarming.client.model.PartField;
import nl.cloudfarming.client.model.FieldPlan;
import nl.cloudfarming.client.planning.PlanAction;
import org.jdesktop.swingx.JXDatePicker;
import org.jdesktop.swingx.JXPanel;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;

/**
 * Plan a new ProductionUnit action.
 * @author Timon Veenstra
 */
public class PlanProductionUnitAction extends PlanAction implements ProductionUnitAction {

    private final String DISPLAY_NAME = NbBundle.getMessage(this.getClass(), "field_plan.plan_production_unit_action.name.name");   
    private static final String CONFIRM_MESSAGE_TITLE = NbBundle.getMessage(LinkProductionUnitToFieldAction.class, "field_plan.plan_production_unit_action.confirm_message.title");    
    private static final String CONFIRM_MESSAGE_FROM = NbBundle.getMessage(LinkProductionUnitToFieldAction.class, "field_plan.plan_production_unit_action.confirm_message.from");     
    
    protected static final String COMBOBOX_RACES_NAME = "racescombobox";
    protected static final String COMBOBOX_CROPS_NAME = "cropscombobox";
    
    private JTextField nameTextField = new JTextField();
    private JXDatePicker startDatePicker = new JXDatePicker();
    private JXDatePicker endDatePicker = new JXDatePicker();
    private Dialog dlg;
    private JButton jButtonOK = new JButton();
    
    private Crop selectedCrop;
    private Race selectedRace;
    
    private JComboBox cropsComboBox = new JComboBox();
    private JComboBox racesComboBox = new JComboBox();
    
    private CropService cropservice = Lookup.getDefault().lookup(CropService.class);   
    private TacticalPlanningService service = Lookup.getDefault().lookup(TacticalPlanningService.class);
    private JList availableFieldsList;

    private JXPanel panel;
            
    private static final AppLogger LOG = AppLogFactory.getLogger(PlanProductionUnitAction.class);
    
    private final MessageEventProducer messageEventProducer = new MessageEventProducer();
    
        
    public PlanProductionUnitAction() {
        putValue(NAME, DISPLAY_NAME);
    }
        
    /**
     * Crop en field
     * @param e Actionevent e
     */
    @Override
    public void actionPerformed(ActionEvent e) {

        //
        // populate the panel with the information about what the user is about to save
        //
        panel = new JXPanel(new MigLayout("wrap 3"));

        cropsComboBox = getCropComboBox();
        racesComboBox = getRacesComboBox();
        racesComboBox.setPreferredSize(new Dimension(150,0));
        JScrollPane fieldScrollPane = getFieldScrollPane();
        // Dirty dimension setting ...
        nameTextField.setPreferredSize(new Dimension(fieldScrollPane.getPreferredSize().width, 0));
        
        
        panel.add(new JLabel(NbBundle.getMessage(this.getClass(), "field_plan.plan_production_unit_action.name.name_textfield")));
        panel.add(nameTextField, "span");

        panel.add(new JLabel(NbBundle.getMessage(this.getClass(), "field_plan.plan_production_unit_action.name.crop")));
        panel.add(cropsComboBox);
        panel.add(racesComboBox);

        panel.add(new JLabel(NbBundle.getMessage(this.getClass(), "field_plan.plan_production_unit_action.name.startDate")));
        panel.add(startDatePicker, "span");

        panel.add(new JLabel(NbBundle.getMessage(this.getClass(), "field_plan.plan_production_unit_action.name.endDate")));
        panel.add(endDatePicker, "span");

        panel.add(new JLabel("Fields"));
        panel.add(fieldScrollPane, "span");

        //
        // create the dialog and add the ok and cancel buttons
        //
        DialogDescriptor dd = new DialogDescriptor(panel, DISPLAY_NAME);
        dd.setOptions(new Object[]{getOkButton(), getCancelButton()});
        dlg = DialogDisplayer.getDefault().createDialog(dd);
        dlg.setVisible(true);
    } 
    
    /**
     * Build and return a combobox with all available crops.
     * @return ComboBox with all available crops
     */
    private JComboBox getCropComboBox(){      
           
        List<Crop> crops = cropservice.getCrops();
        final JComboBox cropComboBox = new JComboBox();
        cropComboBox.setName(COMBOBOX_CROPS_NAME);
        
        if (crops.isEmpty()) {
            cropComboBox.setModel(new DefaultComboBoxModel(new String[]{"NO CROPLIST AVAILABLE"}));
            cropComboBox.setEnabled(false);
        } else {           
            cropComboBox.setModel(new DefaultComboBoxModel(crops.toArray()));         
            
            // Listen for model selection change
            cropComboBox.addItemListener(new ItemListener() {
                
                @Override
                public void itemStateChanged(ItemEvent e) {
                    Object possibleCrop = cropComboBox.getSelectedItem();
                    if(possibleCrop instanceof Crop){
                        selectedCrop = (Crop) possibleCrop;     
                        jButtonOK.setEnabled(false);

                        // Selection changed, reload Race combobox
                        createRaceCBModel();
                    }
                }
            });
            
            // Set first crop as selectedItem 
            selectedCrop = crops.get(0);
            ((DefaultComboBoxModel) cropComboBox.getModel()).setSelectedItem(selectedCrop);
            
            // Enable ComboBox
            cropComboBox.setEnabled(true);
        }
        return cropComboBox;     
    }
     
    /**
     * JComboBox with all Races belonging to the selected crop.
     * @return JComboBox with all races belonging to the selected crop.
     */
    private JComboBox getRacesComboBox() {

        racesComboBox.setName(COMBOBOX_RACES_NAME);
        // Fieldplans comboBox
        racesComboBox.setModel(createRaceCBModel());
        racesComboBox.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {   
                Object possibleRace = racesComboBox.getSelectedItem();
                if(possibleRace instanceof Race){ // SelectedItem can be default-value ( = String) when there are no PU's found for the selected Fieldplan
                    selectedRace = (Race) possibleRace;
                    jButtonOK.setEnabled(true);
                }
            }
        });
        return racesComboBox;
    }
    
    /**
     * Init (or re-init) Race ComboBoxModel
     */
    private DefaultComboBoxModel createRaceCBModel() {
        selectedRace = null;
        
        DefaultComboBoxModel racesComboBoxModel = (DefaultComboBoxModel) racesComboBox.getModel();
        
        // When model is initially created the model will still be null, create here
        if(racesComboBoxModel == null){
            racesComboBoxModel = new DefaultComboBoxModel();
            racesComboBox.setModel(racesComboBoxModel); 
        }
            
        // Find all races that belong to the selected crop
        List<Race> races = cropservice.getRaces(selectedCrop);
        
        if (races.isEmpty()) {
            racesComboBoxModel.removeAllElements();
            racesComboBoxModel.addElement("This crop has no races");
            racesComboBox.setEnabled(false);
            jButtonOK.setEnabled(false);
        } else {
            racesComboBoxModel.removeAllElements();
            for(Race race : races){
                racesComboBoxModel.addElement(race);
            }
            racesComboBox.setEnabled(true);
            jButtonOK.setEnabled(true);
            
            // Set first to active
            selectedRace = races.get(0);
        }
        return racesComboBoxModel;
    }    
            
    /**
     * Create scrollpane containing all Fields.
     * 
     * @return Scrollpane containing all Fields
     */
    private JScrollPane getFieldScrollPane() {
        
        JScrollPane scrollPane = new JScrollPane();
        List<Field> fields = service.findAllFields();
        availableFieldsList = new JList(fields.toArray());

        scrollPane.setViewportView(availableFieldsList);
        return scrollPane;
    }

    /**
     * Creates the dialog ok button
     *
     * @return
     */
    private JButton getOkButton() {
        jButtonOK = new JButton();
        jButtonOK.setText(NbBundle.getMessage(this.getClass(), "field_plan.plan_production_unit_action.name.ok"));
        jButtonOK.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                okButtonActionPerformed();

            }
        });
        return jButtonOK;
    }
    
    /**
     * Method will be called when OK-button is pressed
     */
    private void okButtonActionPerformed(){
        dlg.setVisible(false);

        String name = nameTextField.getText();
        Date startDate = startDatePicker.getDate();
        Date endDate = endDatePicker.getDate();
        
        
        // Get current selected fieldplan from lookup
        FieldPlan fieldPlan = Utilities.actionsGlobalContext().lookup(FieldPlan.class);

        assert(fieldPlan != null); // Should never happen, action can only be called on fieldplan.
        
        // Build PU
        ProductionUnit.Builder productionUnitBuilder = new ProductionUnit.Builder().setCrop(selectedCrop.getKeyName()).setRace(selectedRace.getKeyName()).setFieldPlan(fieldPlan).setName(name).setStartDate(startDate).setEndDate(endDate);
        ProductionUnit productionUnit = service.createProductionUnit(productionUnitBuilder);
        
        StringBuilder fieldsSb = new StringBuilder();
        
        // Loop through selected fields. Create partfield for each, link PU to each.
        for(Object selectedField : availableFieldsList.getSelectedValues()){
            if(selectedField instanceof Field){
                Field field = (Field) selectedField ;
                
                fieldsSb.append("- ");
                fieldsSb.append("(");
                fieldsSb.append(field.getId());
                fieldsSb.append(") ");
                fieldsSb.append(field.getName());
                fieldsSb.append("\n");
                        
                PartField partField = Field.createPartFieldFrom(field, productionUnit);
                
                service.createPartField(partField);
                
                // Add partfield to PU
                productionUnit.addPartField(partField);
            }
        }
        
        // Created production unit {0} ({1}) on fields [{2}] starting on {3} and ending on {4}    
        String confirm_message_text = NbBundle.getMessage(LinkProductionUnitToFieldAction.class, "field_plan.plan_production_unit_action.confirm_message.message_text", productionUnit.getName(), productionUnit.getCrop(), fieldsSb.toString(), productionUnit.getStartDate(), productionUnit.getEndDate());    
        
        Message message = new Message();
        message.setTitle(CONFIRM_MESSAGE_TITLE);
        message.setMessageText(confirm_message_text);
        message.setOrigin(CONFIRM_MESSAGE_FROM);
        message.setDateReceived(new Date());
        messageEventProducer.triggerEvent(new MessageEvent(message, MessageEventKey.NEW_MESSAGE));
        LOG.info(confirm_message_text);     
    }

    /**
     * creates the dialog cancel button
     * @return
     */
    private JButton getCancelButton() {
        JButton jButtonCancel = new JButton();
        jButtonCancel.setText(NbBundle.getMessage(this.getClass(), "field_plan.plan_production_unit_action.name.cancel"));
        jButtonCancel.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                dlg.setVisible(false);
            }
        });
        return jButtonCancel;
    }
    
    JXPanel getPanel() {
        return panel;
    }
}
